package com.shixu.framework.plugins.weixin.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ExecutionException;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;

import com.alibaba.fastjson.JSONObject;
import com.shixu.framework.core.AppContext;
import com.shixu.framework.plugins.weixin.util.HttpKit;
import com.shixu.framework.plugins.weixin.util.WeixinConstant;
import com.shixu.framework.plugins.weixin.util.XStreamFactory;
import com.shixu.framework.util.JsonUtils;
import com.shixu.framework.util.MapUtils;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.mapper.FieldAliasingMapper;

/**
 * 支付相关方法
 *
 */
public class PayService {

    // 发货通知接口
    private static final String DELIVERNOTIFY_URL = "https://api.weixin.qq.com/pay/delivernotify?access_token=";

    /**
     * 参与 paySign 签名的字段包括：appid、timestamp、noncestr、package 以及 appkey。
     * 这里 signType 并不参与签名微信的Package参数
     * @param params
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String getPackage(Map<String, String> params) throws UnsupportedEncodingException {
        String partnerKey = AppContext.getInstance().getString("partnerkey");
        String partnerId = AppContext.getInstance().getString("partnerid");
        String notifyUrl = AppContext.getInstance().getString("notify_url");
        // 公共参数
        params.put("bank_type", "WX");
//        params.put("attach", "yongle");// 附加参数
        params.put("partner", partnerId);
        params.put("notify_url", notifyUrl);
        params.put("input_charset", "UTF-8");
        return packageSign(params, partnerKey);
    }

    /**
     * 构造签名
     * @param params
     * @param encode
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String createSign(Map<String, String> params, boolean encode) throws UnsupportedEncodingException {
        Set<String> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = value.toString();
            }
            if (encode) {
                temp.append(URLEncoder.encode(valueString, "UTF-8"));
            } else {
                temp.append(valueString);
            }
        }
        return temp.toString();
    }

    /**
     * 构造package, 这是我见到的最草蛋的加密，尼玛文档还有错
     * @param params
     * @param paternerKey
     * @return
     * @throws UnsupportedEncodingException 
     */
    private static String packageSign(Map<String, String> params, String paternerKey) throws UnsupportedEncodingException {
        String string1 = createSign(params, false);
        String stringSignTemp = string1 + "&key=" + paternerKey;
        String signValue = DigestUtils.md5Hex(stringSignTemp).toUpperCase();
        String string2 = createSign(params, true);
        return string2 + "&sign=" + signValue;
//    	return null;
    }

    /**
     * 支付签名
     * @param timestamp
     * @param noncestr
     * @param packages
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static String paySign(String timestamp, String noncestr,String packages) throws UnsupportedEncodingException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", AppContext.getInstance().getString("appid"));
        paras.put("timestamp", timestamp);
        paras.put("noncestr", noncestr);
        paras.put("package", packages);
        paras.put("appkey", AppContext.getInstance().getString("paysignkey"));
        // appid、timestamp、noncestr、package 以及 appkey。
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.sha1Hex(string1);
        return paySign;
//    	return null;
    }
    
    /**
     * 支付回调校验签名
     * @param timestamp
     * @param noncestr
     * @param openid
     * @param issubscribe
     * @param appsignature
     * @return
     * @throws UnsupportedEncodingException 
     */
    public static boolean verifySign(long timestamp,
            String noncestr, String openid, int issubscribe, String appsignature) throws UnsupportedEncodingException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", AppContext.getInstance().getString("appid"));
        paras.put("appkey", AppContext.getInstance().getString("paysignkey"));
        paras.put("timestamp", String.valueOf(timestamp));
        paras.put("noncestr", noncestr);
        paras.put("openid", openid);
        paras.put("issubscribe", String.valueOf(issubscribe));
        // appid、appkey、productid、timestamp、noncestr、openid、issubscribe
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.md5Hex(string1);
        return paySign.equalsIgnoreCase(appsignature);
//    		return true;
    }
    
    /**
     * 发货通知签名
     * @param paras
     * @return
     * @throws UnsupportedEncodingException
     * 
     * @参数 appid、appkey、openid、transid、out_trade_no、deliver_timestamp、deliver_status、deliver_msg；
     */
    private static String deliverSign(Map<String, String> paras) throws UnsupportedEncodingException {
        paras.put("appkey", AppContext.getInstance().getString("paysignkey"));
        String string1 = createSign(paras, false);
        String paySign = DigestUtils.sha1Hex(string1);
        return paySign;
//    	return null;
    }
    
    
    /**
     * 发货通知
     * @param access_token
     * @param openid
     * @param transid
     * @param out_trade_no
     * @return
     * @throws IOException 
     * @throws NoSuchProviderException 
     * @throws NoSuchAlgorithmException 
     * @throws KeyManagementException 
     * @throws InterruptedException 
     * @throws ExecutionException 
     */

    public static boolean delivernotify(String access_token, String openid, String transid, String out_trade_no) throws IOException, ExecutionException, InterruptedException {
        Map<String, String> paras = new HashMap<String, String>();
        paras.put("appid", AppContext.getInstance().getString("appid"));
        paras.put("openid", openid);
        paras.put("transid", transid);
        paras.put("out_trade_no", out_trade_no);
        paras.put("deliver_timestamp", (System.currentTimeMillis() / 1000) + "");
        paras.put("deliver_status", "1");
        paras.put("deliver_msg", "ok");
        // 签名
        String app_signature = deliverSign(paras);
        paras.put("app_signature", app_signature);
        paras.put("sign_method", "sha1");
        String json = HttpKit.post(DELIVERNOTIFY_URL.concat(access_token), JSONObject.toJSONString(paras));
        if (StringUtils.isNotBlank(json)) {
            JSONObject object = JSONObject.parseObject(json);
            if (object.containsKey("errcode")) {
                int errcode = object.getIntValue("errcode");
                return errcode == 0;
            }
        }
        return false;
    }
    
    
    public static String getPrePayId(Map<String, String> params) throws Exception{
    	
        String partnerId = AppContext.getInstance().getString("partnerid");
        String notifyUrl = AppContext.getInstance().getString("notify_url");
        // 公共参数
//        params.put("bank_type", "WX");
        params.put("appid", AppContext.getInstance().getString("appid"));
        params.put("mch_id", partnerId);
        params.put("notify_url", notifyUrl);
//        params.put("input_charset", "UTF-8");
        params.put("trade_type", "JSAPI");
    
        
        String signValue = getSign(params);

        params.put("sign", signValue);
        System.out.println("params:"+ JsonUtils.toJson(params));
        
       
        String xml = map2xml(params);
        System.out.println("xml:" + xml);
    	return HttpKit.postXml(WeixinConstant.PREPAY_URL, xml);
    }
    
	/**
	 * 创建预支付定单
	 * @param params
	 * @return
	 * @throws Exception
	 */
	public static String getPreUnifiedId(Map<String, String> params) throws Exception{
    	
        String partnerId = AppContext.getInstance().getString("partnerid");
        String notifyUrl = AppContext.getInstance().getString("notify_url");
        params.put("appid", AppContext.getInstance().getString("appid"));
        params.put("mch_id", partnerId);
        params.put("notify_url", notifyUrl);
        params.put("trade_type", "NATIVE");
    
        
        String signValue = getSign(params);

        params.put("sign", signValue);
        System.out.println("params:"+ JsonUtils.toJson(params));
        
        String xml = map2xml(params);
        System.out.println("xml:" + xml);
    	return HttpKit.postXml(WeixinConstant.PREPAY_URL, xml);
    }
	
    
	public static String getSign(Map<String, String> params) {
		System.out.println(JsonUtils.toJson(params));
		String paysignkey = AppContext.getInstance().getString("paysignkey");
		
		String string1 = null;
		try {
			string1 = createSign(params, false);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		String stringSignTemp = string1 + "&key=" + paysignkey;

		return DigestUtils.md5Hex(stringSignTemp).toUpperCase();
	}
    
    private static String map2xml(Map<String,String> map){
    	Iterator<Entry<String, String>> iter = map.entrySet().iterator();
    	StringBuilder sb = new StringBuilder("<xml>");
    	while (iter.hasNext()){
    		Entry m = iter.next();
    		sb.append("<").append(m.getKey()).append(">");
    		sb.append(m.getValue());
    		sb.append("</").append(m.getKey()).append(">");
    	}
    	sb.append("</xml>");
    	return sb.toString();
    }
    
    /**
     * 
     * @param oauth token
     * @param url
     * @return
     */
    public static String addrSign4JS(String token,String url,String nonceStr,String timeStamp){
    	Map<String, String> paras = new HashMap<String, String>();
        paras.put("appId", AppContext.getInstance().getString("appid"));
        paras.put("url", url);
        paras.put("timestamp", timeStamp);
        paras.put("nonceStr", nonceStr);
        paras.put("accessToken", token);

        // appid、timestamp、noncestr、package 以及 appkey。
        String string1 = null;
		try {
			string1 = createSign(paras, false);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        String addrSign = DigestUtils.sha1Hex(string1);
    	
    	return addrSign;
    }
   
}
